﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using DataBaseLibrary.DBObjectsFB;

namespace DataBaseLibrary.DBInterfaces
{

    /// <summary>
    /// Реализует логику работы с пользователем.
    /// </summary>
    public abstract class User
    {

        public enum Privelegies
        {
            GrandAll = 0, //Все права разрешены
            Operator = 1 //права администратора
        }

        protected  String UserName;
        protected  String Password;
        protected IDBProvider Provider;

        protected Privelegies _Privelegies { get; set; }

        public User(IDBProvider provider, String userName, String password)
        {
            UserName = userName;
            Password = password;
            Provider = provider;
        }

        public User(object ID)
        {
            
        }

        /// <summary>
        /// Создает нового пользователя
        /// </summary>
        public void CreateNewUser(User currentUser, Privelegies privelegies)
        {
            _Privelegies = privelegies;
            MD5 md5 = MD5.Create();
            if (!AddUserToDB(GetMd5Hash(md5, Password)))
            {
                throw new SystemException("Ошибка при добавлении пользовтеля в БД!");
            }
            
        }

        /// <summary>
        /// Берет данные пользователя по его ID и записывает в поля оъекта
        /// </summary>
        /// <param name="ID"></param>
        /// <returns></returns>
        protected abstract void GetUserFromID(object ID);

        /// <summary>
        /// Добавляет пользователя в БД
        /// </summary>
        /// <returns></returns>
        protected abstract bool AddUserToDB(String md5Password);

        /// <summary>
        /// Удаляет пользователя из БД
        /// </summary>
        /// <returns></returns>
        protected abstract bool DeleteUserFromDB(object ID);        

        /// <summary>
        /// Берет md5 пароль из БД
        /// </summary>
        /// <param name="UserName"></param>
        /// <returns></returns>
        protected abstract String GetPasswordFromUser(String UserName);

        #region Функции для работы с MD5 из Microsoft MSDN
        protected string GetMd5Hash(MD5 md5Hash, string input)
        {

            // Convert the input string to a byte array and compute the hash.
            byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

            // Create a new Stringbuilder to collect the bytes
            // and create a string.
            StringBuilder sBuilder = new StringBuilder();

            // Loop through each byte of the hashed data 
            // and format each one as a hexadecimal string.
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }

            // Return the hexadecimal string.
            return sBuilder.ToString();
        }

        // Verify a hash against a string.
        protected bool VerifyMd5Hash(MD5 md5Hash, string input, string hash)
        {
            // Hash the input.
            string hashOfInput = GetMd5Hash(md5Hash, input);

            // Create a StringComparer an compare the hashes.
            StringComparer comparer = StringComparer.OrdinalIgnoreCase;

            if (0 == comparer.Compare(hashOfInput, hash))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        #endregion


        /// <summary>
        /// Берет привелегии по UserName
        /// </summary>
        /// <returns></returns>
        protected abstract Privelegies GetPrivelegiesFromDB();

        /// <summary>
        /// Производит авторизацию пользователя. Считывает привилегии (Privelegies) и для безопасности стирает поле Password!
        /// </summary>
        /// <returns></returns>
        public bool AuthorizeUser()
        {

            String md5Password = GetPasswordFromUser(UserName);


            MD5 md5 = MD5.Create();
            if (!VerifyMd5Hash(md5, Password, md5Password))
            {
                Password = String.Empty;
                return false;
            }


            Password = String.Empty;
            _Privelegies = GetPrivelegiesFromDB();
            return true;
        }

        public void DeleteUser(User currentUser, object ID)
        {
            if (currentUser == null || currentUser._Privelegies == Privelegies.Operator)
            {
                throw new Exception("У Вас не достаточно прав для выполнения данной операции!");
            }

            
            DeleteUserFromDB(ID);
        }

        /// <summary>
        /// Возвращает привилегии данного пользователя
        /// </summary>
        /// <returns></returns>
        public Privelegies GetPrivelegies()
        {
            return _Privelegies;
        }

        public abstract object GetUserId();

    }

    
    public abstract class IDBLogic
    {

        /// <summary>
        /// Первое поле ValueFields и NamesFields - всегда ID
        /// </summary>
        public struct ResultFields
        {
            public string[] NamesFields;
            public List<object[]> ValueFields;
        }

        protected IDBProvider Provider;

        public IDBLogic(IDBProvider provider)
        {
            Provider = provider;
        }


        /// <summary>
        /// Поиск людишек по ФИО, которые передаются в объекта Individual
        /// </summary>
        /// <param name="provider"></param>
        /// <param name="Individual"></param>
        /// <returns></returns>
        public abstract ResultFields SearchIndividualsFio(Individual Individual);

        /// <summary>
        /// Поиск договоров к/п по ФИО
        /// </summary>
        public abstract ResultFields SearchSalesContract(Individual Individual);

        /// <summary>
        /// Поиск заявлений по ФИО
        /// </summary>
        public abstract ResultFields SearchDeclaration(Individual Individual);

        /// <summary>
        /// Поиск заявлений на ВУ к/п по ФИО
        /// </summary>
        public abstract ResultFields SearchDeclarationVu(Individual Individual);

        /// <summary>
        /// Берет вех пользователей из БД
        /// </summary>
        /// <returns></returns>
        protected abstract ResultFields GetAllUsersFromDB();


        /// <summary>
        /// Возвращает всех пользователей из БД. Доступ  только для администратора!
        /// </summary>
        /// <param name="currentUser"></param>
        /// <returns></returns>
        public ResultFields GetAllUsers(User currentUser)
        {
            if (currentUser == null || currentUser.GetPrivelegies() == User.Privelegies.Operator)
            {
                throw new Exception("Доступ запрещен! Обратитесь к администратору!");
            }

            return GetAllUsersFromDB();
        }


        /// <summary>
        /// История создания/изменения документов из БД
        /// </summary>
        /// <returns></returns>
        protected abstract ResultFields GetAllDocumentsHystoryFromDB(DateTime dateStart, DateTime dateStop);

        

        /// <summary>
        /// Получить всю историю создания/изменения документов
        /// </summary>
        /// <param name="currentUser"></param>
        /// <param name="dateStart"></param>
        /// <param name="dateStop"></param>
        /// <returns></returns>
        public ResultFields GetDocumentsHistory(User currentUser, DateTime dateStart, DateTime dateStop)
        {
            if (currentUser == null || currentUser.GetPrivelegies() == User.Privelegies.Operator)
            {
                throw new Exception("Доступ запрещен! Обратитесь к администратору!");
            }

            try
            {
                return GetAllDocumentsHystoryFromDB(dateStart, dateStop);
            }
            catch (Exception err)
            {
                
                throw new Exception(err.Message);
            }
        }


        /// <summary>
        /// Добавить действия с документами в БД
        /// </summary>
        /// <param name="cuurentUser"></param>
        /// <param name="NumberDocument"></param>
        /// <param name="TypeDocument"></param>
        /// <param name="Action"></param>
        /// <param name="date"></param>
        /// <param name="price"></param>
        public abstract void AddDocumentHistory(User cuurentUser, String NumberDocument, String TypeDocument, String Action,
            DateTime date, Double price);

        

    }
}
